package com.lanyou.cook.web;

import java.net.URLEncoder;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.lanyou.cook.common.Constants;
import com.lanyou.cook.datadictionary.KettleJobScheduleCycleUnit;
import com.lanyou.cook.datadictionary.UserLogOpt;
import com.lanyou.cook.entity.domain.InterfaceSchedule;
import com.lanyou.cook.entity.domain.SystemInterface;
import com.lanyou.cook.entity.domain.userManagement.User;
import com.lanyou.cook.repository.InterfaceScheduleRepository;
import com.lanyou.cook.repository.SystemInterfaceRepository;
import com.lanyou.cook.service.InterfaceScheduleService;
import com.lanyou.cook.service.UserLogService;
import com.lanyou.cook.service.security.UserSessionService;
import com.lanyou.cook.util.DateUtil;
import com.lanyou.cook.web.param.InterfaceScheduleParam;


/**
 * 接口调度相关业务的控制层
 * @author 曾族根
 *
 */
@RestController
@RequestMapping(Constants.BASE_URL_API + "/interfaceSchedules")
public class InterfaceScheduleController {

	@Autowired
	private InterfaceScheduleRepository interfaceScheduleRepository;
	@Autowired
	private UserSessionService userSessionService;
	@Autowired
	private InterfaceScheduleService interfaceScheduleService;
	
	@Autowired
	private SystemInterfaceRepository systemInterfaceRepository;
	
	@Autowired
	private UserLogService userLogService;
	
	@PersistenceContext
	private EntityManager entityManager;

	/**
	 * 查询特定条件下的接口调度集合
	 * @param param	类型:InterfaceScheduleParam 待查询的接口调度参数实体
	 * @param pageable 类型:Pageable 待查询的分页参数实体
	 * @return
	 */
	@RequestMapping("/search/findByExample")
	@RequiresPermissions(value={"interfaceSchedulingManagement:view","interfaceSchedulingManagement:maintain"},logical=Logical.OR)
	public Page<InterfaceSchedule> findByExample(InterfaceScheduleParam param,
			 Pageable pageable) {
		Specification<InterfaceSchedule> spec = new Specification<InterfaceSchedule>() {
			@Override
			public Predicate toPredicate(Root<InterfaceSchedule> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicatesList = new ArrayList<>();
				
				// 调度名称
				if(StringUtils.isNotBlank(param.getName())){
					predicatesList.add(cb.like(root.get("name"), '%' + param.getName() + '%'));
				}
				
				// 接口名称
				if(StringUtils.isNotBlank(param.getInterfaceName())){
					predicatesList.add(cb.like(root.get("systemInterface").get("jobName"), '%' + param.getInterfaceName() + '%'));
				}
				
				// 领域系统
				Path<String> pathOwnerFieldSystemId = root.get("systemInterface").get("ownerFieldSystem").get("id");
				if(StringUtils.isNotBlank(param.getFieldSystemId())){
					predicatesList.add(cb.equal(pathOwnerFieldSystemId, param.getFieldSystemId()));
				} else {
					// 默认查当前登录用户所管理的领域系统
					Collection<String> fieldSystemIds = userSessionService.findFieldSystemIdsOfCurrentAuthenticatedUserCanManage();
					if(!CollectionUtils.isEmpty(fieldSystemIds)){
						predicatesList.add(pathOwnerFieldSystemId.in(fieldSystemIds));
					}else {
						predicatesList.add(cb.notEqual(cb.literal(1), 1));
					}
				}
				// 领域
				if(StringUtils.isNotBlank(param.getFieldId())){
					predicatesList.add(cb.equal(root.get("systemInterface").get("ownerFieldSystem").get("field").get("id"), param.getFieldId()));
				}
				
				// 运行周期
				if(StringUtils.isNotBlank(param.getRunWay())){
					Path<String> pathRunWay = root.get("runWay");
					
					switch(param.getRunWay()){
					case "once":
						predicatesList.add(cb.equal(pathRunWay, KettleJobScheduleCycleUnit.Once.ValueCode));
						break;
					case "cycle":
						predicatesList.add(cb.notEqual(pathRunWay, KettleJobScheduleCycleUnit.Once.ValueCode));
					}
				}
				//是否设置
				if(StringUtils.isNotBlank(param.getIfSet())){
					
					switch(param.getIfSet()){
					case "set":
						predicatesList.add(cb.isNotNull(root.get("scheduleServer").get("id")));
						break;
					case "unSet":
						predicatesList.add(cb.isNull(root.get("scheduleServer").get("id") ));
					}
				}
				
				DynaBean fixedDates = DateUtil.fixBeginTimeAndEndTime(param.getBeginOfCreateTime(), param.getEndOfCreateTime());
				Date fixedBeginTime = (Date)fixedDates.get("begin");
				Date fixedEndTime = (Date)fixedDates.get("end");
				
				Path<Date> pathDate = root.get("createTime");	
				predicatesList.add(cb.or(cb.isNull(pathDate), cb.between(pathDate, fixedBeginTime, fixedEndTime)));
				
				query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
				return null;
			}
		};
		
		return interfaceScheduleRepository.findAll(spec, pageable);
	}
	
	/**
	 * 判断当前要操作的调度的状态
	 * @param id 类型:String 接口调度ID
	 * @return 类型:String 正在调度返回true,未调度返回false
	 */
	@RequestMapping(value = "/search/checkScheduleStatus", produces = "application/json")
	public String checkIsCanDelete(String id) {
		JsonObject result = new JsonObject();
		result.addProperty("isCanDelete", interfaceScheduleService.checkIsCanDelete(id));
		return result.toString();
	}
//	/**
//	 * 是否重名
//	 * @param name 调度名
//	 * @param originalId 调度ID
//	 * @return
//	 */
//	@RequestMapping(value = "/checkIsCanSave", produces = "application/json")
//	public String checkIsCanSave(String name,String originalId){
//		InterfaceSchedule schedule = interfaceScheduleRepository.findByName(name);
//		if (schedule != null) {
//			if (!StringUtils.equals(schedule.getId(), originalId)) {
//				JsonObject result = new JsonObject();
//				result.addProperty("isCanSave", false);
//				result.addProperty("reason", "数据库中已存在，不能保存！");
//				return result.toString();
//			}
//		}
//
//		JsonObject result = new JsonObject();
//		result.addProperty("isCanSave", true);
//		return result.toString();
//	}
//	/**
//	 * 检验调度是否被引用，如果被引用给予提醒
//	 * @param kettleJobId
//	 * @return
//	 */
//	@RequestMapping(value = "/RemindIsAdd", produces = "application/json")
//	public String RemindIsAdd(long kettleJobId){
//		List<InterfaceSchedule> schedule = interfaceScheduleRepository.findBySystemInterface_KettleJob_Id(kettleJobId);
//		if(schedule!=null){
//			JsonObject result = new JsonObject();
//			result.addProperty("isCanAdd", false);
//			result.addProperty("reason", "该作业已经被某个调度引用，是否新建一个相同作业的调度");
//			return result.toString();
//		}
//		JsonObject result = new JsonObject();
//		result.addProperty("isCanAdd", true);
//		return result.toString();
//	}
	
	/**
	 * 获取用户的邮箱地址
	 * @return 类型:String 邮箱地址数据
	 */
	@RequestMapping(value="/search/getUserEmail",produces="application/json")
	public String getUserEmail(){
		
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> cq = cb.createTupleQuery();

		// 构建FROM和JOIN部分
		Root<User> rootUser = cq.from(User.class);
		List<Predicate> predicatesList = new ArrayList<>();
		
		predicatesList.add(cb.isNotNull(rootUser.get("role")));
		cq.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
		
		// 构建SELECT部分
		cq.multiselect(rootUser.get("userCode").alias("userCode"),
				rootUser.get("userName").alias("userName"),
				rootUser.get("emailAddress").alias("emailAddress"));

		// 执行查询
		TypedQuery<Tuple> q = entityManager.createQuery(cq);
		List<Tuple> queryResult = q.getResultList();
		JsonArray jsonDatas = new JsonArray();
		for (Tuple tuple : queryResult) {
			String userCode = tuple.get("userCode",String.class);
			String  emailAddress = tuple.get("emailAddress", String.class);
			String  userName = tuple.get("userName", String.class);
			
			JsonObject jo = new JsonObject();
			jo.addProperty("userCode", userCode);
			jo.addProperty("userName", userName);
			jo.addProperty("emailAddress", emailAddress);
			jsonDatas.add(jo);
		}
		return jsonDatas.toString();
	}
	private static FastDateFormat fastDateFormat1 = FastDateFormat.getInstance(Constants.DATETIME_PATTERN_1);
	
	@RequestMapping(value = "/addOrupdateInterfaceScheduling", produces = "application/json", method = RequestMethod.POST)
	@RequiresPermissions(value={"interfaceSchedulingManagement:maintain"})
	@Transactional
	public String addOrupdateInterfaceScheduling(@RequestBody InterfaceScheduleParam interfaceScheduleParam) throws ParseException {

		JsonObject result = new JsonObject();
		boolean flag = false;
		if (StringUtils.equals(interfaceScheduleParam.getRunWay(), KettleJobScheduleCycleUnit.Day.ValueCode)
				&& StringUtils.isBlank(interfaceScheduleParam.getDayOfWeek())) {
			result.addProperty("backValue", false);
			result.addProperty("error", "1");
			result.addProperty("reason", "请选择至少一个调度周期（周一到周日）再进行保存操作！");
			return result.toString();
		}
		
		InterfaceSchedule interfaceSchedule = interfaceScheduleRepository.findOne(InterfaceSchedule.idSpecification(interfaceScheduleParam.getId()));
		
		InterfaceSchedule schedule = interfaceScheduleRepository.findByName(interfaceScheduleParam.getName());
		if (schedule != null) {
			if (!StringUtils.equals(schedule.getId(), interfaceScheduleParam.getId())) {
				result.addProperty("backValue", false);
				result.addProperty("error","1");
				result.addProperty("reason", "存在同名调度，不能保存！");
				return result.toString();	
			}
		}
		if(interfaceSchedule == null){
			interfaceSchedule = new InterfaceSchedule();
			flag = true;
			if(!interfaceScheduleParam.isPass()){
				List<InterfaceSchedule> schedules = interfaceScheduleRepository.findBySystemInterface_Id(interfaceScheduleParam.getSystemInterfaceId());
				if(!schedules.isEmpty()){
					result.addProperty("backValue", false);
					result.addProperty("error","2");
					result.addProperty("reason", "该作业已经建立调度【"+schedules.get(0).getName()+"】,是否继续？");
					return result.toString();
				}
			}
		}
		
		if(StringUtils.equals(interfaceScheduleParam.getRunWay(),KettleJobScheduleCycleUnit.Second.ValueCode)){
			if(interfaceScheduleParam.getRunCyc()<10){
				result.addProperty("backValue", false);
				result.addProperty("error","3");
				result.addProperty("reason", "不允许设置执行周期小于10秒的调度，请修改周期！");
				return result.toString();
			}
		}

		SystemInterface systemInterface = systemInterfaceRepository
				.findOne(SystemInterface.idSpecification(interfaceScheduleParam.getSystemInterfaceId()));
		String code = systemInterface.getJobCode();
		if(StringUtils.contains(code, "ETL_发布方编码")||
				StringUtils.equals(systemInterface.getTecStandard(), "")||
				StringUtils.equals(systemInterface.getSenderDBType(), "")||
				StringUtils.equals(systemInterface.getSenderDBType(), "")||
				StringUtils.equals(systemInterface.getReceiverDBType(), "")||
				StringUtils.equals(systemInterface.getSendKettleDataSource(), "")||
				StringUtils.equals(systemInterface.getReceiverKettleDataSource(), "")||
				StringUtils.equals(systemInterface.getInterfaceScene(), "")
				){
			result.addProperty("backValue", false);
			result.addProperty("error","4");
			result.addProperty("reason", "此接口未设置完整信息，请前往【数据库接口管理】完善信息后再继续本操作！");
			return result.toString();
		}
		interfaceSchedule.setName(interfaceScheduleParam.getName());
		interfaceSchedule.setRunWay(interfaceScheduleParam.getRunWay());
		interfaceSchedule.setDayOfWeek(interfaceScheduleParam.getDayOfWeek());
		interfaceSchedule.setRunCyc(interfaceScheduleParam.getRunCyc());
		if(!StringUtils.isEmpty(interfaceScheduleParam.getBeginTime())){
			interfaceSchedule.setBeginTime(fastDateFormat1.parse(interfaceScheduleParam.getBeginTime()));
		}else{
			interfaceSchedule.setBeginTime(null);
		}
		if(!StringUtils.isEmpty(interfaceScheduleParam.getEndTime())){
			interfaceSchedule.setEndTime(fastDateFormat1.parse(interfaceScheduleParam.getEndTime()));
		}else{
			interfaceSchedule.setEndTime(null);
		}
		interfaceSchedule.setRunStatus(interfaceScheduleParam.getRunStatus());
		interfaceSchedule.setRemark(interfaceScheduleParam.getRemark());
		interfaceSchedule.setErrSendTo(interfaceScheduleParam.getErrSendTo());
		interfaceSchedule.setSystemInterface(systemInterface);
		
		interfaceSchedule.setOverTimes(interfaceScheduleParam.getOverTimes());
		interfaceSchedule.setSendEmailType(interfaceScheduleParam.getSendEmailType());
		interfaceSchedule.setErrSendToFail(interfaceScheduleParam.getErrSendToFail());
		interfaceSchedule.setMaxSendEmailNum(interfaceScheduleParam.getMaxSendEmailNum());
		interfaceSchedule.setIsAgainExecutJob(interfaceScheduleParam.getIsAgainExecutJob());
		interfaceScheduleRepository.save(Arrays.asList(interfaceSchedule));

		// 记录用户日志
		if(flag){
			userLogService.save(UserLogOpt.MaintenanceDispatch, null,
					String.format("新增了接口调度“%s”的信息", interfaceSchedule.getName()));
		}else{
			userLogService.save(UserLogOpt.MaintenanceDispatch, null,
					String.format("修改了接口调度“%s”的信息", interfaceSchedule.getName()));
		}
		
		result.addProperty("backValue", true);
		return result.toString();
	}
	
	
	@RequestMapping(value = "/deleteScheduling", produces = "application/json", method = RequestMethod.DELETE)
	@RequiresPermissions(value={"interfaceSchedulingManagement:maintain"})
	@Transactional
	public String deleteScheduling(String id) {
		JsonObject result = new JsonObject();
		InterfaceSchedule interfaceSchedule = interfaceScheduleRepository.findOne(InterfaceSchedule.idSpecification(id));
		
		
		interfaceScheduleRepository.delete(Arrays.asList(interfaceSchedule));
		userLogService.save(UserLogOpt.MaintenanceDispatch, null, String.format("删除 了接口调度“%s”", interfaceSchedule.getName()));
		result.addProperty("backValue", true);
		return result.toString();
	}
	/**
	 * 导出
	 * @param username
	 * @return
	 */
	@RequestMapping("/findExport")
    @ResponseBody
	@RequiresPermissions(value={"interfaceSchedulingManagement:view","interfaceSchedulingManagement:maintain"},logical=Logical.OR)
	public Object findExport(InterfaceScheduleParam param,HttpServletResponse response) {
		Specification<InterfaceSchedule> spec = new Specification<InterfaceSchedule>() {
			@Override
			public Predicate toPredicate(Root<InterfaceSchedule> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicatesList = new ArrayList<>();
				
				// 调度名称
				if(StringUtils.isNotBlank(param.getName())){
					predicatesList.add(cb.like(root.get("name"), '%' + param.getName() + '%'));
				}
				
				// 接口名称
				if(StringUtils.isNotBlank(param.getInterfaceName())){
					predicatesList.add(cb.like(root.get("systemInterface").get("jobName"), '%' + param.getInterfaceName() + '%'));
				}
				
				// 领域系统
				Path<String> pathOwnerFieldSystemId = root.get("systemInterface").get("ownerFieldSystem").get("id");
				if(StringUtils.isNotBlank(param.getFieldSystemId())){
					predicatesList.add(cb.equal(pathOwnerFieldSystemId, param.getFieldSystemId()));
				} else {
					// 默认查当前登录用户所管理的领域系统
					Collection<String> fieldSystemIds = userSessionService.findFieldSystemIdsOfCurrentAuthenticatedUserCanManage();
					if(!CollectionUtils.isEmpty(fieldSystemIds)){
						predicatesList.add(pathOwnerFieldSystemId.in(fieldSystemIds));
					}else {
						predicatesList.add(cb.notEqual(cb.literal(1), 1));
					}
				}
				// 领域
				if(StringUtils.isNotBlank(param.getFieldId())){
					predicatesList.add(cb.equal(root.get("systemInterface").get("ownerFieldSystem").get("field").get("id"), param.getFieldId()));
				}
				
				// 运行周期
				if(StringUtils.isNotBlank(param.getRunWay())){
					Path<String> pathRunWay = root.get("runWay");
					
					switch(param.getRunWay()){
					case "once":
						predicatesList.add(cb.equal(pathRunWay, KettleJobScheduleCycleUnit.Once.ValueCode));
						break;
					case "cycle":
						predicatesList.add(cb.notEqual(pathRunWay, KettleJobScheduleCycleUnit.Once.ValueCode));
					}
				}
				//是否设置
				if(StringUtils.isNotBlank(param.getIfSet())){
					
					switch(param.getIfSet()){
					case "set":
						predicatesList.add(cb.isNotNull(root.get("scheduleServer").get("id")));
						break;
					case "unSet":
						predicatesList.add(cb.isNull(root.get("scheduleServer").get("id") ));
					}
				}
				
				DynaBean fixedDates = DateUtil.fixBeginTimeAndEndTime(param.getBeginOfCreateTime(), param.getEndOfCreateTime());
				Date fixedBeginTime = (Date)fixedDates.get("begin");
				Date fixedEndTime = (Date)fixedDates.get("end");
				Path<Date> pathDate = root.get("createTime");	
				predicatesList.add(cb.or(cb.isNull(pathDate), cb.between(pathDate, fixedBeginTime, fixedEndTime)));
				
				query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
				return null;
			}
		};
		List<InterfaceSchedule> interfaceSchedules =  interfaceScheduleRepository.findAll(spec);
		 
		 try {
				//1、创建工作簿
				HSSFWorkbook workbook = new HSSFWorkbook();
				interfaceScheduleService.exportExcel(interfaceSchedules, workbook);
				response.setContentType("application/vnd.ms-excel");
				String filename="接口调度表";
		    	 response.addHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(filename,"UTF-8")+".xls");
		    	 response.setCharacterEncoding("utf-8"); 
				ServletOutputStream outputStream = response.getOutputStream();
				if(outputStream != null){
					workbook.write(outputStream);
					 outputStream.flush();
			    	  outputStream.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		return interfaceSchedules;
		
	}
}
